package com.jichangxiu.dynamic.test.entity;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Pattern;

/**
 * @author Jcx
 * @date 2022/10/30 10:58
 */
public class Record extends LinkedHashMap<String, Object> implements Serializable {

    private static final long serialVersionUID = 1L;

    private Record() {
    }

    /**
     * 获取一个值
     */
    @Override
    public Object get(Object key) {
        if ("this".equals(key)) {
            return this;
        }
        return super.get(key);
    }

    /**
     * 如果为空，则返回默认值
     */
    public Object get(Object key, Object defaultValue) {
        Object value = get(key);
        if (ObjectUtil.isEmpty(value)) {
            return defaultValue;
        }
        return value;
    }

    /**
     * 转为 String 并返回
     */
    public String getStr(String key) {
        Object value = get(key);
        if (ObjectUtil.isEmpty(value)) {
            return null;
        }
        return String.valueOf(value);
    }

    /**
     * 如果为空，则返回默认值
     */
    public String getStr(String key, String defaultValue) {
        Object value = get(key);
        if (ObjectUtil.isEmpty(value)) {
            return defaultValue;
        }
        return String.valueOf(value);
    }

    /**
     * 转为 int 并返回
     */
    public int getInt(String key) {
        Object value = get(key);
        if (ObjectUtil.isEmpty(value)) {
            return 0;
        }
        return Integer.parseInt(String.valueOf(value));
    }

    /**
     * 转为 int 并返回，同时指定默认值
     */
    public int getInt(String key, int defaultValue) {
        Object value = get(key);
        if (ObjectUtil.isEmpty(value)) {
            return defaultValue;
        }
        return Integer.parseInt(String.valueOf(value));
    }

    /**
     * 转为 long 并返回
     */
    public long getLong(String key) {
        Object value = get(key);
        if (ObjectUtil.isEmpty(value)) {
            return 0;
        }
        return Long.parseLong(String.valueOf(value));
    }

    /**
     * 转为 double 并返回
     */
    public double getDouble(String key) {
        Object value = get(key);
        if (ObjectUtil.isEmpty(value)) {
            return 0.0;
        }
        return Double.parseDouble(String.valueOf(value));
    }

    /**
     * 转为 boolean 并返回
     */
    public boolean getBoolean(String key) {
        Object value = get(key);
        if (ObjectUtil.isEmpty(value)) {
            return false;
        }
        return Boolean.parseBoolean(String.valueOf(value));
    }

    /**
     * 转为 Date 并返回，根据自定义格式
     */
    public Date getDateByFormat(String key, String format) {
        try {
            return new SimpleDateFormat(format).parse(getStr(key));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 转为 Date 并返回，根据格式： yyyy-MM-dd
     */
    public Date getDate(String key) {
        return getDateByFormat(key, "yyyy-MM-dd");
    }

    /**
     * 转为 Date 并返回，根据格式： yyyy-MM-dd HH:mm:ss
     */
    public Date getDateTime(String key) {
        return getDateByFormat(key, "yyyy-MM-dd HH:mm:ss");
    }

    /**
     * 获取集合(必须原先就是个集合，否则会创建个新集合并返回)
     */
    public List<Object> getList(String key) {
        Object value = get(key);
        List<Object> list = null;
        if (ObjectUtil.isEmpty(value)) {
            list = new ArrayList<Object>();
        } else if (value instanceof List) {
            list = (List<Object>) value;
        } else {
            list = new ArrayList<Object>();
            list.add(value);
        }
        return list;
    }

    /**
     * 获取集合 (指定泛型类型)
     */
    public <T> List<T> getList(String key, Class<T> cs) {
        List<Object> list = getList(key);
        List<T> list2 = new ArrayList<T>();
        for (Object obj : list) {
            T objC = getValueByClass(obj, cs);
            list2.add(objC);
        }
        return list2;
    }

    /**
     * 获取集合(逗号分隔式)，(指定类型)
     */
    public <T> List<T> getListByComma(String key, Class<T> cs) {
        String listStr = getStr(key);
        if (StrUtil.isEmpty(listStr)) {
            return new ArrayList<>();
        }
        // 开始转化
        String[] arr = listStr.split(",");
        List<T> list = new ArrayList<T>();
        for (String str : arr) {
            if (cs == int.class || cs == Integer.class || cs == long.class || cs == Long.class) {
                str = str.trim();
            }
            T objC = getValueByClass(str, cs);
            list.add(objC);
        }
        return list;
    }

    /**
     * 根据指定类型从 map 中取值，返回实体对象
     */
    public <T> T getModel(String key, Class<T> cs) {
        try {
            return getValueByClass(this.get(key), cs);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 根据指定类型从 map 中取值，返回实体对象
     */
    public <T> T getModel(Class<T> cs) {
        try {
            return getModelByObject(cs.newInstance());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 从 map 中取值，塞到一个对象中
     */
    public <T> T getModelByObject(T obj) {
        // 获取类型
        Class<?> cs = obj.getClass();
        // 循环复制
        for (Field field : cs.getDeclaredFields()) {
            try {
                // 获取对象
                Object value = this.get(field.getName());
                if (ObjectUtil.isEmpty(value)) {
                    continue;
                }
                field.setAccessible(true);
                Object valueConvert = getValueByClass(value, field.getType());
                field.set(obj, valueConvert);
            } catch (IllegalArgumentException | IllegalAccessException e) {
                throw new RuntimeException("属性取值出错：" + field.getName(), e);
            }
        }
        return obj;
    }

    /**
     * 将指定值转化为指定类型并返回
     */
    public static <T> T getValueByClass(Object obj, Class<T> cs) {
        String obj2 = String.valueOf(obj);
        Object obj3 = null;
        if (cs.equals(String.class)) {
            obj3 = obj2;
        } else if (cs.equals(int.class) || cs.equals(Integer.class)) {
            obj3 = Integer.valueOf(obj2);
        } else if (cs.equals(long.class) || cs.equals(Long.class)) {
            obj3 = Long.valueOf(obj2);
        } else if (cs.equals(short.class) || cs.equals(Short.class)) {
            obj3 = Short.valueOf(obj2);
        } else if (cs.equals(byte.class) || cs.equals(Byte.class)) {
            obj3 = Byte.valueOf(obj2);
        } else if (cs.equals(float.class) || cs.equals(Float.class)) {
            obj3 = Float.valueOf(obj2);
        } else if (cs.equals(double.class) || cs.equals(Double.class)) {
            obj3 = Double.valueOf(obj2);
        } else if (cs.equals(boolean.class) || cs.equals(Boolean.class)) {
            obj3 = Boolean.valueOf(obj2);
        } else {
            obj3 = (T) obj;
        }
        return (T) obj3;
    }

    /**
     * 给指定 key 添加一个默认值（只有在这个 key 原来无值的情况先才会set进去）
     */
    public void setDefaultValue(String key, Object defaultValue) {
        if (StrUtil.isNotEmpty(key)) {
            set(key, defaultValue);
        }
    }

    /**
     * set 一个值，连缀风格
     */
    public Record set(String key, Object value) {
        // 防止敏感key
        if ("this".equals(key.toLowerCase())) {
            return this;
        }
        put(key, value);
        return this;
    }

    /**
     * 将一个Map塞进Record
     */
    public Record setMap(Map<String, ?> map) {
        if (ObjectUtil.isNotEmpty(map)) {
            for (String key : map.keySet()) {
                this.set(key, map.get(key));
            }
        }
        return this;
    }

    /**
     * 将一个对象解析塞进 Record
     */
    public Record setModel(Object model) {
        if (ObjectUtil.isEmpty(model)) {
            return this;
        }
        Field[] fields = model.getClass().getDeclaredFields();
        for (Field field : fields) {
            try {
                field.setAccessible(true);
                boolean isStatic = Modifier.isStatic(field.getModifiers());
                if (!isStatic) {
                    this.set(field.getName(), field.get(model));
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        return this;
    }

    /**
     * 将 json 字符串解析后塞进 Record
     */
    public Record setJsonStr(String jsonStr) {
        try {
            Map<String, Object> map = new ObjectMapper().readValue(jsonStr, Map.class);
            return this.setMap(map);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * delete 一个值，连缀风格
     */
    public Record delete(String key) {
        remove(key);
        return this;
    }

    /**
     * 清理所有 value 为 null 的字段
     */
    public Record clearNull() {
        Iterator<String> iterator = this.keySet().iterator();
        while (iterator.hasNext()) {
            String key = iterator.next();
            if (StrUtil.isEmpty(key)) {
                iterator.remove();
                this.remove(key);
            }
        }
        return this;
    }

    /**
     * 清理指定 key
     */
    public Record clearIn(String... keys) {
        List<String> keys2 = Arrays.asList(keys);
        Iterator<String> iterator = this.keySet().iterator();
        while (iterator.hasNext()) {
            String key = iterator.next();
            if (keys2.contains(key)) {
                iterator.remove();
                this.remove(key);
            }
        }
        return this;
    }

    /**
     * 清理掉不在列表中的 key
     */
    public Record clearNotIn(String... keys) {
        List<String> keys2 = Arrays.asList(keys);
        Iterator<String> iterator = this.keySet().iterator();
        while (iterator.hasNext()) {
            String key = iterator.next();
            if (!keys2.contains(key)) {
                iterator.remove();
                this.remove(key);
            }
        }
        return this;
    }

    /**
     * 清理掉所有 key
     */
    public Record clearAll() {
        clear();
        return this;
    }

    /**
     * 构建一个 Record 并返回
     */
    public static Record getRecord() {
        return new Record();
    }

    /**
     * 构建一个 Record 并返回
     */
    public static Record getRecord(String key, Object value) {
        return new Record().set(key, value);
    }

    /**
     * 构建一个 Record 并返回
     */
    public static Record getRecord(Map<String, ?> map) {
        return new Record().setMap(map);
    }

    /**
     * 将一个对象集合解析成为 Record
     */
    public static Record getRecordByModel(Object model) {
        return Record.getRecord().setModel(model);
    }

    /**
     * 将一个对象集合解析成为 Record 集合
     */
    public static List<Record> getRecordByList(List<?> list) {
        List<Record> listMap = new ArrayList<>();
        for (Object model : list) {
            listMap.add(getRecordByModel(model));
        }
        return listMap;
    }

    /**
     * 克隆指定 key，返回一个新的 Record
     */
    public Record cloneKeys(String... keys) {
        Record record = new Record();
        for (String key : keys) {
            record.set(key, this.get(key));
        }
        return record;
    }

    /**
     * 克隆所有 key，返回一个新的 Record
     */
    public Record cloneRecord() {
        Record record = new Record();
        for (String key : this.keySet()) {
            record.set(key, this.get(key));
        }
        return record;
    }

    /**
     * 将所有 key 转为大写
     */
    public Record toUpperCase() {
        Record record = new Record();
        for (String key : this.keySet()) {
            record.set(key.toUpperCase(), this.get(key));
        }
        this.clearAll().setMap(record);
        return this;
    }

    /**
     * 将所有 key 转为小写
     */
    public Record toLowerCase() {
        Record record = new Record();
        for (String key : this.keySet()) {
            record.set(key.toLowerCase(), this.get(key));
        }
        this.clearAll().setMap(record);
        return this;
    }

    /**
     * 将所有 key 中下划线转为中划线模式 ( kebab-case 风格)
     */
    public Record toKebabCase() {
        Record record = new Record();
        for (String key : this.keySet()) {
            record.set(wordEachKebabCase(key), this.get(key));
        }
        this.clearAll().setMap(record);
        return this;
    }

    /**
     * 将所有 key 中下划线转为小驼峰模式
     */
    public Record toHumpCase() {
        Record record = new Record();
        for (String key : this.keySet()) {
            record.set(wordEachBigFs(key), this.get(key));
        }
        this.clearAll().setMap(record);
        return this;
    }

    /**
     * 将所有 key 中小驼峰转为下划线模式
     */
    public Record humpToLineCase() {
        Record record = new Record();
        for (String key : this.keySet()) {
            record.set(wordHumpToLine(key), this.get(key));
        }
        this.clearAll().setMap(record);
        return this;
    }

    private static final Pattern compile = Pattern.compile("[0-9]*");

    /**
     * 指定 key 是否为数字
     */
    public boolean isNumber(String key) {
        String value = getStr(key);
        if (StrUtil.isEmpty(value)) {
            return false;
        }
        return compile.matcher(value).matches();
    }

    /**
     * 转为 JSON 字符串
     */
    public String toJsonStr() {
        try {
            return new ObjectMapper().writeValueAsString(this);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 转为 JSON 字符串, 带格式的
     */
    public String toJsonFormatStr() {
        try {
            return JSON.toJSONString(this, String.valueOf(true));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 返回当前 request 请求的的所有参数
     */
    public static Record getRequestRecord() {
        // 大善人SpringMVC提供的封装
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (servletRequestAttributes == null) {
            throw new RuntimeException("当前线程非JavaWeb环境");
        }
        // 当前request
        HttpServletRequest request = servletRequestAttributes.getRequest();
        if (request.getAttribute("currentRecord") == null || request.getAttribute("currentRecord") instanceof Record == false) {
            initRequestRecord(request);
        }
        return (Record) request.getAttribute("currentRecord");
    }

    /**
     * 初始化当前 request 的 Record
     */
    private static void initRequestRecord(HttpServletRequest request) {
        Record record = new Record();
        // 获取所有参数
        Map<String, String[]> parameterMap = request.getParameterMap();
        for (String key : parameterMap.keySet()) {
            try {
                // 获得values
                String[] values = parameterMap.get(key);
                if (values.length == 1) {
                    record.set(key, values[0]);
                } else {
                    List<String> list = new ArrayList<String>();
                    for (String v : values) {
                        list.add(v);
                    }
                    record.set(key, list);
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        request.setAttribute("currentRecord", record);
    }

    /**
     * 验证返回当前线程是否为 JavaWeb 环境
     */
    public static boolean isJavaWeb() {
        // 大善人SpringMVC提供的封装
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (servletRequestAttributes == null) {
            return false;
        }
        return true;
    }

    /**
     * 将一个一维集合转换为树形集合
     */
    public static List<Record> listToTree(List<Record> list, String idKey, String parentIdKey, String childListKey) {
        // 声明新的集合，存储tree形数据
        List<Record> newTreeList = new ArrayList<Record>();
        // 声明hash-Map，方便查找数据
        Record hash = new Record();
        // 将数组转为Object的形式，key为数组中的id
        for (int i = 0; i < list.size(); i++) {
            Record json = (Record) list.get(i);
            hash.put(json.getStr(idKey), json);
        }
        // 遍历结果集
        for (int j = 0; j < list.size(); j++) {
            // 单条记录
            Record aVal = (Record) list.get(j);
            // 在hash中取出key为单条记录中pid的值
            Record hashVp = (Record) hash.get(aVal.get(parentIdKey, "").toString());
            // 如果记录的pid存在，则说明它有父节点，将她添加到孩子节点的集合中
            if (hashVp != null) {
                // 检查是否有child属性，有则添加，没有则新建
                if (hashVp.get(childListKey) != null) {
                    @SuppressWarnings("unchecked") List<Record> ch = (List<Record>) hashVp.get(childListKey);
                    ch.add(aVal);
                    hashVp.put(childListKey, ch);
                } else {
                    List<Record> ch = new ArrayList<Record>();
                    ch.add(aVal);
                    hashVp.put(childListKey, ch);
                }
            } else {
                newTreeList.add(aVal);
            }
        }
        return newTreeList;
    }

    /**
     * 指定字符串的字符串下划线转大写模式
     */
    private static String wordEachBig(String str) {
        String newStr = "";
        for (String s : str.split("_")) {
            newStr += wordFirstBig(s);
        }
        return newStr;
    }

    /**
     * 返回下划线转小驼峰形式
     */
    private static String wordEachBigFs(String str) {
        return wordFirstSmall(wordEachBig(str));
    }

    /**
     * 将指定单词首字母大写
     */
    private static String wordFirstBig(String str) {
        return str.substring(0, 1).toUpperCase() + str.substring(1, str.length());
    }

    /**
     * 将指定单词首字母小写
     */
    private static String wordFirstSmall(String str) {
        return str.substring(0, 1).toLowerCase() + str.substring(1, str.length());
    }

    /**
     * 下划线转中划线
     */
    private static String wordEachKebabCase(String str) {
        return str.replaceAll("_", "-");
    }

    /**
     * 驼峰转下划线
     */
    private static String wordHumpToLine(String str) {
        return str.replaceAll("[A-Z]", "_$0").toLowerCase();
    }

}
